{%mainunit bitcoin_p2p.pas}

{$IFDEF INTERFACE}
type
  { TNetAddress is designed to later be able to also work
    with IP-V6 addresses but currently only V4 is implemended.}
  TNetAddress = class(TMsg)

    { same services as in the version message }
    Services: UInt64;

    { (12 bytes 00 00 00 00 00 00 00 00 00 00 FF FF,
      followed by the 4 bytes of the IPv4 address).
      IP Address and Port are transmitted *** BIG ENDIAN ***}
    Address: array[0..15] of Byte;

    { Port will be swapped to machine endianness, address left as is. }
    Port: Word;

    constructor Create(AServices: QWord; AStrAddr4: String; APort: Word); overload;
    procedure ParseAndProcess; override;
    procedure SerializeToStream(AStream: TStringStream);
    function GetStrAddr4: String;
    procedure SetFromStrAddr4(StrAddr4: String);
  end;

{$ENDIF}
{$IFDEF IMPLEMENTATION}

constructor TNetAddress.Create(AServices: QWord; AStrAddr4: String; APort: Word);
begin
  Services := AServices;
  Port := APort;
  SetFromStrAddr4(AStrAddr4);
end;

procedure TNetAddress.ParseAndProcess;
begin
  Services := ReadQWord;
  ReadBuffer(Address, SizeOf(Address));
  ReadBuffer(Port, SizeOf(Port));
  {$IFDEF ENDIAN_LITTLE} // port comes in big endian
  Port := SwapEndian(Port);
  {$ENDIF}
  AddAddress4ToDb(GetStrAddr4, Port);
end;

procedure TNetAddress.SerializeToStream(AStream: TStringStream);
begin
  FSendData := AStream;
  WriteQWord(Services);
  WriteBuffer(Address, SizeOf(Address));
  WriteWord(Port);
end;

function TNetAddress.GetStrAddr4: String;
var
  NetAddr4: in_addr;
begin
  Move(Address[12], NetAddr4{%H-}, 4);
  Result := NetAddrToStr(NetAddr4.s_addr);
end;

procedure TNetAddress.SetFromStrAddr4(StrAddr4: String);
var
  NetAddr4: in_addr;
begin
  NetAddr4 := StrToNetAddr(StrAddr4);
  FillByte(Address[0], 10, 0);
  FillByte(Address[10], 2, $ff);
  Move(NetAddr4, Address[12], 4);
end;

{$ENDIF}
